package org.future.task.core.manager;

import org.future.task.core.annotate.AutoBond;
import org.future.task.core.cache.ParamCache;
import org.future.task.core.flow.TransformImpl;
import org.future.task.core.handler.Connection;
import org.future.task.core.handler.DefaultConnectionImpl;
import org.future.task.core.handler.RunnableTask;
import org.future.task.core.handler.TransForm;
import org.future.task.core.monitor.Monitor;
import org.future.task.core.task.Task;
import org.future.task.core.util.ThreadPoolUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;

public class SystemManager {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private List<Task> tasks;

    private int defaultCapacity;

    private ThreadPoolExecutor threadPoolExecutor;

    private Map<String, Object> publicSingleBeans;

    private TransForm<Object> transForm;

    private Connection publicConnection;

    private Monitor monitor;

    public SystemManager() {
    }

    public SystemManager(List<Task> tasks) {
        this.tasks = tasks;
    }

    public SystemManager(List<Task> tasks, Map<String, Object> publicSingleBeans) {
        this.tasks = tasks;
        this.publicSingleBeans = publicSingleBeans;
    }

    public SystemManager(List<Task> tasks, Connection publicConnection) {
        this.tasks = tasks;
        this.publicConnection = publicConnection;
    }

    public SystemManager(List<Task> tasks, ThreadPoolExecutor threadPoolExecutor, Map<String, Object> publicSingleBeans, TransForm<Object> transForm) {
        this.tasks = tasks;
        this.threadPoolExecutor = threadPoolExecutor;
        this.publicSingleBeans = publicSingleBeans;
        this.transForm = transForm;
    }

    public SystemManager(List<Task> tasks, ThreadPoolExecutor threadPoolExecutor, Map<String, Object> publicSingleBeans, TransForm<Object> transForm, Connection publicConnection) {
        this(tasks, 0, threadPoolExecutor, publicSingleBeans, transForm, publicConnection);
    }

    public SystemManager(List<Task> tasks, int defaultCapacity, ThreadPoolExecutor threadPoolExecutor, Map<String, Object> publicSingleBeans, TransForm<Object> transForm, Connection publicConnection) {
        this.tasks = tasks;
        this.defaultCapacity = defaultCapacity;
        this.threadPoolExecutor = threadPoolExecutor;
        this.publicSingleBeans = publicSingleBeans;
        this.transForm = transForm;
        this.publicConnection = publicConnection;
    }

    public TransForm<Object> getTransForm() {
        return transForm;
    }

    public void setTransForm(TransForm<Object> transForm) {
        this.transForm = transForm;
    }

    public Map<String, Object> getPublicSingleBeans() {
        return publicSingleBeans;
    }

    public void setPublicSingleBeans(Map<String, Object> publicSingleBeans) {
        this.publicSingleBeans = publicSingleBeans;
    }

    public Monitor getMonitor() {
        return monitor;
    }

    public void setMonitor(Monitor monitor) {
        this.monitor = monitor;
    }

    public void systemInit() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        if (threadPoolExecutor == null) {
            threadPoolExecutor = new ThreadPoolUtils().getDefaultThreadPool("task", 1);
        }
        if (this.publicConnection != null) {
            ParamCache.setPublicConnection(publicConnection);
        }

        //开启监控清理
        if (monitor != null) {
            clearTimer();
        }

        for (Task task : tasks) {
            addTaskToThisPool(task);
        }

    }


    private void clearTimer() {
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                monitor.reset();
            }
        };

        //设置执行时间
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);//每天
        //定制每天的21:09:00执行，
        calendar.set(year, month, day, 0, 0, 0);
        Date date = calendar.getTime();
        Timer timer = new Timer();

        int period = 24 * 60 * 60 * 1000;
        //每天的date时刻执行task，每隔2秒重复执行
        timer.schedule(task, date, period);
        //每天的date时刻执行task, 仅执行一次
//        timer.schedule(task, date);
    }

    public void addTaskToThisPool(Task task) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        String queueName = task.getQueueName();
        int threadSize = task.getThreadSize();
        boolean useCache = task.isUseCache();
        Connection connection = task.getConnection();
        if (useCache) {
            if (connection == null) {
                connection = this.publicConnection;
            }
        } else {
            int nativeQueueSize = task.getNativeQueueSize();
            if (nativeQueueSize != 0) {
                defaultCapacity = nativeQueueSize;
            }

            connection = new DefaultConnectionImpl(defaultCapacity);
        }

        ParamCache.setConnection(queueName, connection);

        TransForm transForm = task.getTransForm();
        String runnableClass = task.getRunnableClass();
        Map<String, Object> singleBeans = task.getSingleBeans();
        Class<?> aClass = Class.forName(runnableClass);

        //实例化对象 并注入
        RunnableTask runnableTask = autoBond(aClass, singleBeans);

        runnableTask.setQueueName(queueName);
        if (transForm != null) {
            runnableTask.setTransForm(transForm);
        } else if (this.transForm != null) {
            runnableTask.setTransForm(this.transForm);
        } else {
            runnableTask.setTransForm(new TransformImpl());
        }

        if (monitor != null) {
            runnableTask.setMonitor(monitor);
        }


        synchronized (threadPoolExecutor) {
            threadPoolExecutor.setCorePoolSize(threadPoolExecutor.getPoolSize() + threadSize);
        }

        int readBatch = task.getReadBatch();

        for (int i = 0; i < threadSize; i++) {
            TaskFactory taskFactory;
            if (readBatch != 0) {
                taskFactory = new TaskFactory(runnableTask, readBatch);
            } else {
                taskFactory = new TaskFactory(runnableTask);
            }
            //将实例化的对象放入线程池
            threadPoolExecutor.execute(taskFactory);
        }
        logger.info("队列 {} 监听线程加入线程池，线程数 {}，队列类型 {}", queueName, threadSize, connection.getType());
    }


    private RunnableTask autoBond(Class<?> clazz, Map<String, Object> singleBeans) throws IllegalAccessException, InstantiationException {
        Field[] fields = clazz.getDeclaredFields();
        RunnableTask obj = (RunnableTask) clazz.newInstance();
        if (fields.length == 0) {
            return obj;
        }
        for (Field field : fields
        ) {
            try {
                if (field.isAnnotationPresent(AutoBond.class)) {
                    Object object = null;
                    if (singleBeans != null && singleBeans.size() != 0) {
                        object = singleBeans.get(field.getName());
                    }
                    if (object == null && this.publicSingleBeans != null && this.publicSingleBeans.size() != 0) {
                        object = this.publicSingleBeans.get(field.getName());
                    }
                    if (object == null) {
                        //增加注解式简单常量注入
                        AutoBond annotation = field.getAnnotation(AutoBond.class);
                        if (String.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultString();
                        } else if (int.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultInt();
                        } else if (boolean.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultBoolean();
                        } else if (float.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultFloat();
                        } else if (double.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultDouble();
                        } else if (long.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultLong();
                        } else if (byte.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultByte();
                        } else if (short.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultShort();
                        } else if (char.class.isAssignableFrom(field.getType())) {
                            object = annotation.defaultChar();
                        }
                    }
                    field.setAccessible(true);
                    field.set(obj, object);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return obj;
    }

}
